package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodConstantProperties vodConstantProperties;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private VodService vodService;


    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
        //  声明一个集合
        List<TrackInfo> trackInfoList = new ArrayList<>();
        //  1.  trackCount 等于0或大于0; 等于0的时候，就是购买本集.
        //  获取当前声音对象
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        //  远程调用已购买的声音列表集合.
        Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(userPaidTrackList, "用户购买声音列表为空！");
        List<Long> trackIdList = userPaidTrackList.getData();
        // Assert.notNull( trackIdList, "用户购买声音Id列表为空！"); 允许为空。
        if (trackCount > 0) {
            //  需要出去已购买的集数;
            //  select * from track_info track where order_num > 6 and album_id = 1429 limit 10;
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
            //  除去已购买的声音集合列表.
            if (!CollectionUtils.isEmpty(trackInfoList)) {
                //  select * from track_info track where order_num > 6 and album_id = 1429 and id not in (48243, 48244) limit 10;
                wrapper.notIn(TrackInfo::getId, trackIdList);
            }
            //  拼接limit ;
            wrapper.last(" limit " + trackCount);
            trackInfoList = trackInfoMapper.selectList(wrapper);
        } else {
            //  说明购买的是本集;
            trackInfoList.add(trackInfo);
        }
        //  返回集合
        return trackInfoList;
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
        //  根据声音Id获取到当前专辑对应的声音列表;
        TrackInfo trackInfo = this.getById(trackId);
        //  获取声音列表： 所有列表：6-25
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum()).select(TrackInfo::getId);
        List<Long> trackIdList = trackInfoMapper.selectList(wrapper).stream().map(TrackInfo::getId).collect(Collectors.toList());

        //  获取用户已购买的声音集合列表! 已购买：9,10,11
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "用户购买声音列表为空！");
        List<Long> trackIdPaidList = trackIdListResult.getData();
        Assert.notNull(trackIdPaidList, "用户购买声音Id列表为空！");
        //  两个集合要去重获取差集：
        List<Long> trackIdAllPaidList = trackIdList.stream().filter(tId -> !trackIdPaidList.contains(tId)).collect(Collectors.toList());
        //  获取专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
        //  构建 map 集合了.
        /*
            Map<String, Object> map = new HashMap<>();
            map.put("name","本集"); // 显示文本
            map.put("price",albumInfo.getPrice()); // 专辑声音对应的价格
            map.put("trackCount",0); // 记录购买集数
            list.add(map);
         */
        //  声明一个集合来存储map集合
        List<Map<String, Object>> list = new ArrayList<>();
        if (trackIdAllPaidList.size() > 0) {
            //  声明一个 map 集合.
            Map<String, Object> map = new HashMap<>();
            map.put("name", "本集"); // 显示文本
            map.put("price", albumInfo.getPrice()); // 专辑声音对应的价格
            map.put("trackCount", 0); // 记录购买集数
            list.add(map);
        }
        //  判断 后10集
        if (trackIdAllPaidList.size() > 10) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后10集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("10"))); // 专辑声音对应的价格
            map.put("trackCount", 10); // 记录购买集数
            list.add(map);
        }
        if (trackIdAllPaidList.size() > 0 && trackIdAllPaidList.size() <= 10) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后" + trackIdAllPaidList.size() + "集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
            map.put("trackCount", trackIdAllPaidList.size()); // 记录购买集数
            list.add(map);
        }
        //  判断 后20集
        if (trackIdAllPaidList.size() > 20) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后20集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("20"))); // 专辑声音对应的价格
            map.put("trackCount", 20); // 记录购买集数
            list.add(map);
        }
        if (trackIdAllPaidList.size() > 10 && trackIdAllPaidList.size() <= 20) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后" + trackIdAllPaidList.size() + "集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
            map.put("trackCount", trackIdAllPaidList.size()); // 记录购买集数
            list.add(map);
        }
        //  判断 后20集
        if (trackIdAllPaidList.size() > 30) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后30集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("30"))); // 专辑声音对应的价格
            map.put("trackCount", 30); // 记录购买集数
            list.add(map);
        }
        if (trackIdAllPaidList.size() > 20 && trackIdAllPaidList.size() <= 30) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后" + trackIdAllPaidList.size() + "集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(trackIdAllPaidList.size())))); // 专辑声音对应的价格
            map.put("trackCount", trackIdAllPaidList.size()); // 记录购买集数
            list.add(map);
        }
        //  最多买50集
        if (trackIdAllPaidList.size() > 50) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "后50集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("50"))); // 专辑声音对应的价格
            map.put("trackCount", 50); // 记录购买集数
            list.add(map);
        }
        //  返回集合
        return list;
    }

    @Override
    public void trackStatUpdate(TrackStatMqVo trackStatMqVo) {
        //  本质就是执行更新操作.
        //  update track_stat set stat_num = stat_num + 1 where track_id = 1 and stat_type = '0701';
        trackInfoMapper.updateTrackStatNum(trackStatMqVo.getTrackId(), trackStatMqVo.getCount(), trackStatMqVo.getStatType());
        if (trackStatMqVo.getStatType().equals(SystemConstant.TRACK_STAT_PLAY)) {
            //  更新专辑:
            //  update album_stat set stat_num = stat_num + 1 where album_id = 1 and stat_type = '0401';
            albumInfoMapper.updateAlbumStatNum(trackStatMqVo.getAlbumId(), trackStatMqVo.getCount(), SystemConstant.ALBUM_STAT_PLAY);
        }
        //        else if (trackStatMqVo.getStatType().equals(SystemConstant.TRACK_STAT_COMMENT)){
        //            //  更新评论
        //            albumInfoMapper.updateAlbumStatNum(trackStatMqVo.getAlbumId(),trackStatMqVo.getCount(),SystemConstant.ALBUM_STAT_COMMENT);
        //        }


    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
        //  1.  根据专辑Id 与 分页条件 查询声音列表;
        IPage<AlbumTrackListVo> albumTrackListPage = trackInfoMapper.selectAlbumTrackPage(albumTrackListVoPage, albumId);
        //  获取到专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(albumId);
        //  2.  判断用户Id 是否为空
        if (null == userId) {
            //  判断专辑类型， 0101-免费、0102-vip免费、0103-付费
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
                //  不是免费专辑，需要将isShowPaidMark这个属性设置为true;
                //  除试听声音之外的都需要设置为付费;
                //  获取到专辑对应的免费试听集数;
                Integer tracksForFree = albumInfo.getTracksForFree();
                //  order_num > tracksForFree; 就是需要设置为付费的声音;
                albumTrackListPage.getRecords().stream().filter(track -> track.getOrderNum() > tracksForFree).forEach(track -> track.setIsShowPaidMark(true));
            }
        } else {
            //  声明一个变量来标识是否需要付费.
            boolean isPaid = false;
            // 用户登录
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
                //  0102-vip免费
                //  用户不是vip 或 是vip但是已经过期了 都需要付费
                Result<UserInfoVo> userInfoVoResult = this.userInfoFeignClient.getUserInfoVo(userId);
                Assert.notNull(userInfoVoResult.getData(), "用户信息为空！");
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                if (userInfoVo.getIsVip() == 0 || (userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date()))) {
                    //  需要付费
                    isPaid = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
                //  付费
                isPaid = true;
            }
            //  统一处理需要付费的情况
            if (isPaid) {
                //  1.  获取到需要付费的声音列表; 除去试听的声音.
                List<AlbumTrackListVo> albumTrackNeedPaidListVoList = albumTrackListPage.getRecords().stream().filter(track -> track.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
                //  获取到需要付费的声音Id 列表：
                List<Long> trackIdList = albumTrackNeedPaidListVoList.stream().map(track -> track.getTrackId()).collect(Collectors.toList());
                //  需要远程调用判断这个用户是否购买过声音Id 或 专辑. 购买声音需要设置 map的key=trackId value=1;购买过  否则value=0;没有购买过
                Result<Map<Long, Integer>> mapResult = this.userInfoFeignClient.userIsPaidTrack(albumId, trackIdList);
                Assert.notNull(mapResult, "远程调用失败！");
                Map<Long, Integer> map = mapResult.getData();
                Assert.notNull(map, "远程调用失败！");
                //  循环遍历
                albumTrackNeedPaidListVoList.forEach(albumTrackListVo -> {
                    //  if (map.get(albumTrackListVo.getTrackId()) == 0) {
                    //      albumTrackListVo.setIsShowPaidMark(true);
                    //  } else {
                    //      albumTrackListVo.setIsShowPaidMark(false);
                    //  }
                    //  将上述代码变为三元运算形式
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0 ? true : false);
                });
            }
        }
        //  返回数据
        return albumTrackListPage;
    }

    @Override
    public void updateTrackInfoById(Long trackId, TrackInfoVo trackInfoVo) {
        //  track_info;
        TrackInfo trackInfo = this.getById(trackId);
        //  可能修改声音！ 你怎么知道用户是否修改了声音? 原有数据库的文件Id
        String originMediaFileId = trackInfo.getMediaFileId();
        //  获取前端页面传递的文件Id
        String mediaFileId = trackInfoVo.getMediaFileId();
        //  赋值：
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //  原有的与现在的比较
        if (!originMediaFileId.equals(mediaFileId)) {
            //  如果不相等，则说明修改了声音！
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileId);
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            //  删除vod中的声音;
            vodService.removeMedia(originMediaFileId);
        }
        //  赋值声音Id
        trackInfo.setId(trackId);
        //  更新数据
        trackInfoMapper.updateById(trackInfo);
        //  track_stat 删除可选
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfoById(Long trackId) {
        //  album_info中的包含声音总数要-1;
        //  已知只有一个声音Id，需要获取到专辑对象！
        TrackInfo trackInfo = this.getById(trackId);
        //  根据专辑Id获取到专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
        //  判断
        if (null != albumInfo) {
            //  总数要减一;
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        }
        //  添加一行代码！
        albumInfoMapper.updateById(albumInfo);
        //  执行逻辑删除：track_info; track_stat; album_info.include_track_count-1;
        trackInfoMapper.deleteById(trackId);
        //  track_stat
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        //  删除云点播中的数据：
        vodService.removeMedia(trackInfo.getMediaFileId());

        //  track_info; 1 2 3;  1001;  1001 total=3;  2条声音删除了;  track_info 1 3->2;
        //  update track_info set order_num = order_num - 1 where album_id = albumId and is_deleted = 0 and order_num > order_num;
        trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());

    }


    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> voPage, TrackInfoQuery trackInfoQuery) {
        //  需要查询声音与声音统计信息，此时需要多表关联查询.
        return trackInfoMapper.selectUserTrackPage(voPage, trackInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //	track_info
        TrackInfo trackInfo = new TrackInfo();
        //	属性拷贝：
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //	user_id
        trackInfo.setUserId(userId);
        //  order_num 第一种方式：查询声音表中同一张专辑的最大order_num; 第二种：专辑包含声音总数include_track_count + 1;
        int orderNum = 0;
        //	查询专辑表中声音总数； 1. 查询专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (null != albumInfo) {
            orderNum = albumInfo.getIncludeTrackCount() + 1;
        }
        trackInfo.setOrderNum(orderNum);
        //	media_duration media_size media_type 等数据为空！ 调用云点播的api获取流媒体数据！
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        //	赋值流媒体数据
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfoMapper.insert(trackInfo);
        //	track_stat - 统计信息：
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
        // 	album_info
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        this.albumInfoMapper.updateById(albumInfo);

    }

    @Transactional(rollbackFor = Exception.class)
    public void saveTrackStat(Long trackId, String statType) {
        //  创建对象
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(new Random().nextInt(100));
        trackStatMapper.insert(trackStat);
    }

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        //	初始化客户端对象
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        //	构建上传请求
        VodUploadRequest request = new VodUploadRequest();
        //	获取本地上传路径
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        request.setMediaFilePath(tempPath);
        //	调用上传请求：
        try {
            VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
            log.info("Upload FileId = {}", response.getFileId());
            //	创建一个map 对象
            Map<String, Object> map = new HashMap<>();
            map.put("mediaFileId", response.getFileId());
            map.put("mediaUrl", response.getMediaUrl());
            //	返回数据
            return map;
        } catch (Exception e) {
            // 业务方进行异常处理
            log.error("Upload Err", e);
        }
        return null;
    }
}
